#include "types.h"
#include "signal.h"
#include "user.h"
#include "barrier.c"
#include "FSSP.h"


soldier_state statesFunction[4][16] = {
  {Quiet,Quiet,Laying,Quiet,Ready,Ready,0,0,Quiet,0,Laying,Standing,Quiet,Standing,0,0}
,{Ready,Ready,Quiet,Laying,Quiet,Ready,Laying,0,Standing,0,Quiet,Fire,Quiet,Ready,Laying,0}
,{Laying,Standing,Quiet,Quiet,Quiet,Quiet,Ready,Ready,Laying,0,Laying,Laying,Ready,Fire,0,0}
,{Quiet,Standing,Laying,Quiet,Ready,0,0,Fire,Standing,0,0,Standing,Quiet,Standing,Fire,0}
};
soldier_state leftStatesFunction[4][4] = {
{Quiet,Quiet,Laying,Quiet},
{Standing,0,Quiet,Fire},
{0,0,Ready,Ready},
{Quiet,Standing,Fire,0}};
soldier_state rightStatesFunction[4][4] = {
{Quiet,Ready,Quiet,0},
{0,Laying,0,Laying},
{0,Quiet,0,Fire},
{0,0,0,0}};

int FSSP_isFinished()
{
      int i=0;
      for(i=0;i<numOfSoldiers;i++)
      {
	if(states[i] != Fire)		// then there is an unready soldier
	     return 0;
      }
      return 1; 			// all soldiers in fire state - FSSP is finished
}

void FSSP_printTurnArray()
{
  int i;
      for(i=0;i<numOfSoldiers;i++)
      {
	printf(1,"%d ",states[i]);
      }
      printf(1,"\n");
}

soldier_state FSSP_calcNextState(struct soldier* s) 
{
  soldier_state leftState,rightState;
  //read left soldier state:
  if(s->id>0)
	   leftState = states[(s->id)-1]; 
  else		// if the general
	   leftState = X;
  //read right soldier state:  
  if((s->id+1)<numOfSoldiers)
	   rightState = states[(s->id)+1]; 
  else		// if the right soldier
	   rightState = X;	   
  //soldier_state stateFunc[] = statesFunction[s->state][;
  if(rightState != X && leftState != X)
	return statesFunction[s->state][(leftState << 2) + rightState];
  
  if (leftState==X)
	return leftStatesFunction[s->state][rightState];
  if (rightState==X)
	return rightStatesFunction[s->state][leftState];
   return 0;
}

void FSSP_soldier_step(void* sol)
{
   struct soldier* s = (struct soldier*)sol;
   while(FSSP_isFinished() == 0)
  {
      // first step: check if finished and calc your next state
      s->state = FSSP_calcNextState(s);
      /**** DEBUG ****/
      //printf(1,"soldier %d changed his state to: %d \n",s->id,s->state);
      /****/
      barrier_pass(s->turn);		// finished his turn first step
      // second step: update states array
      states[s->id] = s->state;
      barrier_pass(s->turn);		// finished his turn second step
  }
}

int main(int argc, char *argv[])
{
  numOfSoldiers = atoi(argv[1]);
  int i;  
  
  // array init
  struct soldier* soldiers[numOfSoldiers];		//main soldiers array:
  //soldiers = malloc(sizeof(struct soldier*)*numOfSoldiers);
  states = malloc(sizeof(soldier_state)*numOfSoldiers);
  for(i=0;i<numOfSoldiers;i++)
  {
      soldiers[i] = malloc(sizeof(struct soldier));
  }
  // general
  soldiers[0]->state = Ready;
  states[0] = Ready;
  //other soldiers
  for(i=1;i<numOfSoldiers;i++)
  {
      soldiers[i]->state = Quiet;
      states[i] = Quiet;
  }
  
  // barrier init
 
  struct barrier* turn;
  turn = malloc(sizeof(struct barrier));
  barrier_init(turn,numOfSoldiers + 1);  			// the waiting for the turn to end: all the soldiers + the main thread, who is printing
  // threadtable init
  
  uthread_init();
  // barrier signing and threads creation
  for(i=0;i<numOfSoldiers;i++)
  {
      soldiers[i]->turn = turn;
      soldiers[i]->id = uthread_create(FSSP_soldier_step,soldiers[i]) - 1;
  }
  // main thread iterations
  while(FSSP_isFinished() == 0)
  {
      // first step: check if finished and print states
      FSSP_printTurnArray();
      barrier_pass(turn);		// finished his turn first step
      // second step: wait for others
      barrier_pass(turn);		// finished his turn second step
  }
  FSSP_printTurnArray();
  /*
  */
  exit();
}




